<template>
	<div>
		<div ref="point" :class="classes" :style="styles">
			<slot></slot>
		</div>
		<div v-show="slot" :style="slotStyle"></div>
	</div>
</template>

<script lang="ts">
	import Anes from "../base";
	import { Prop, Component } from "vue-property-decorator";
	@Component
	export default class Affix extends Anes {
		@Prop({ type: Number, default: 0 }) offsetTop!: number;
		@Prop() offsetBottom!: number;
		@Prop({ type: Boolean, default: false }) useCapture!: boolean;

		prefixCls = "ivu-affix";
		affix = false;
		styles = {};
		slot = false;
		slotStyle = {};

		get offsetType() {
			let type = "top";
			if (this.offsetBottom >= 0) {
				type = "bottom";
			}

			return type;
		}
		get classes() {
			return [
				{
					[`${this.prefixCls}`]: this.affix
				}
			];
		}
		mounted() {
			this.$options.name = "Affix";
			//            window.addEventListener('scroll', this.handleScroll, false);
			//            window.addEventListener('resize', this.handleScroll, false);
			this.on()(window, "scroll", this.handleScroll, this.useCapture);
			this.on()(window, "resize", this.handleScroll, this.useCapture);
			this.$nextTick(() => {
				this.handleScroll();
			});
		}
		beforeDestroy() {
			//            window.removeEventListener('scroll', this.handleScroll, false);
			//            window.removeEventListener('resize', this.handleScroll, false);
			this.off()(window, "scroll", this.handleScroll, this.useCapture);
			this.off()(window, "resize", this.handleScroll, this.useCapture);
		}

		getScroll(target: Window, top: boolean) {
			const prop = top ? "pageYOffset" : "pageXOffset";
			const method = top ? "scrollTop" : "scrollLeft";

			let ret = target[prop];

			if (typeof ret !== "number") {
				ret = window.document.documentElement[method];
			}

			return ret;
		}

		getOffset(element: Element) {
			const rect = element.getBoundingClientRect();

			const scrollTop = this.getScroll(window, true);
			const scrollLeft = this.getScroll(window, false);

			const docEl = window.document.body;
			const clientTop = docEl.clientTop || 0;
			const clientLeft = docEl.clientLeft || 0;

			return {
				top: rect.top + scrollTop - clientTop,
				left: rect.left + scrollLeft - clientLeft
			};
		}

		handleScroll() {
			const affix = this.affix;
			const scrollTop = this.getScroll(window, true);
			const elOffset = this.getOffset(this.$el);
			const windowHeight = window.innerHeight;
			const elHeight = this.$el.getElementsByTagName("div")[0].offsetHeight;

			// Fixed Top
			if (
				elOffset.top - this.offsetTop < scrollTop &&
				this.offsetType == "top" &&
				!affix
			) {
				this.affix = true;
				this.slotStyle = {
					width: (this.$refs.point as HTMLElement).clientWidth + "px",
					height: (this.$refs.point as HTMLElement).clientHeight + "px"
				};
				this.slot = true;
				this.styles = {
					top: `${this.offsetTop}px`,
					left: `${elOffset.left}px`,
					width: `${(this.$el as HTMLElement).offsetWidth}px`
				};

				this.$emit("on-change", true);
			} else if (
				elOffset.top - this.offsetTop > scrollTop &&
				this.offsetType == "top" &&
				affix
			) {
				this.slot = false;
				this.slotStyle = {};
				this.affix = false;
				this.styles = {};

				this.$emit("on-change", false);
			}

			// Fixed Bottom
			if (
				elOffset.top + this.offsetBottom + elHeight > scrollTop + windowHeight &&
				this.offsetType == "bottom" &&
				!affix
			) {
				this.affix = true;
				this.styles = {
					bottom: `${this.offsetBottom}px`,
					left: `${elOffset.left}px`,
					width: `${(this.$el as HTMLElement).offsetWidth}px`
				};

				this.$emit("on-change", true);
			} else if (
				elOffset.top + this.offsetBottom + elHeight < scrollTop + windowHeight &&
				this.offsetType == "bottom" &&
				affix
			) {
				this.affix = false;
				this.styles = {};

				this.$emit("on-change", false);
			}
		}
	}
</script>

<style>
</style>